package com.qfedu.scode.core;

import com.aliyun.oss.common.utils.IOUtils;
import com.qfedu.scode.config.SystemConfig;
import com.qfedu.scode.dto.DbConfigDto;
import com.qfedu.scode.dto.ProjectConfigDto;
import com.qfedu.scode.dto.TbFieldDto;
import com.qfedu.scode.util.AliOssUtil;
import com.qfedu.scode.util.CompressUtil;
import com.qfedu.scode.util.FileUtil;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.ClasspathResourceLoader;

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import static com.qfedu.scode.util.DatabaseUtil.parseType;
import static com.qfedu.scode.util.DatabaseUtil.readInfo;
import static com.qfedu.scode.util.DateUtil.getTime;
import static com.qfedu.scode.util.FileUtil.createDir;
import static com.qfedu.scode.util.NameParseUtil.parseParamName;
import static com.qfedu.scode.util.NameParseUtil.parseTableName;

/**
 * @program: StartCoding
 * @description: 生成器
 * @author: Feri(邢朋辉)
 * @create: 2021-01-05 17:47
 */
public class CodeGen {
    /**
     * 根据配置生成Java源码
     * @param configDto 项目配置信息
     * @param dbConfigDto 数据库配置信息*/
    public static String createJava(ProjectConfigDto configDto, DbConfigDto dbConfigDto){
        //读取数据库的内容
        Map<String, Map<String,String>> map=readInfo(dbConfigDto);
        //加载模板 8个 挨个生成
        //包-路径
        String baseDir=createDir(configDto.getPkname());
        //实例化Beetl的加载器
        ClasspathResourceLoader loader=new ClasspathResourceLoader("btl/");
        try{
            GroupTemplate groupTemplate=new GroupTemplate(loader, Configuration.defaultConfiguration());
            for(String clz:map.keySet()){
                StringBuffer bufferInsert=new StringBuffer();
                StringBuffer bufferAll=new StringBuffer();
                String entityName=parseTableName(clz);
                if(entityName!=null && entityName.length()>0) {
                    //实现实体层的源码
                    Template entity = groupTemplate.getTemplate("/EntityTem.btl");
                    Map<String, Object> entityMap = new LinkedHashMap<>();
                    entityMap.put("entitypkname", configDto.getPkname() + ".entity");
                    entityMap.put("projectname", configDto.getPname());
                    entityMap.put("projectdes", configDto.getPdesc());
                    entityMap.put("author", configDto.getPauthor());
                    entityMap.put("entityname", entityName);
                    entityMap.put("projecttime", getTime());
                    ArrayList<TbFieldDto> list = new ArrayList<>();
                    Map<String, String> fields = map.get(clz);
                    bufferInsert.append("insert into " + clz + "(");
                    StringBuffer bufferValues = new StringBuffer();
                    for (String f : fields.keySet()) {
                        list.add(new TbFieldDto(f, parseType(fields.get(f))));
                        bufferInsert.append(f + ",");
                        bufferValues.append("#{" + f + "},");
                    }
                    bufferInsert.deleteCharAt(bufferInsert.length() - 1);
                    bufferInsert.append(") values(");
                    bufferValues.deleteCharAt(bufferValues.length() - 1);
                    bufferInsert.append(bufferValues + ")");
                    bufferAll.append("select * from " + clz);

                    entityMap.put("fields", list);
                    entity.binding(entityMap);
                    entity.renderTo(new FileOutputStream(baseDir + "/entity/" + entityMap.get("entityname") + ".java"));
                    //实现持久层的源码
                    Template dao = groupTemplate.getTemplate("/EntityDaoTem.btl");
                    Map<String, Object> daoMap = new LinkedHashMap<>();
                    daoMap.put("daopkname", configDto.getPkname() + ".dao");
                    daoMap.put("entitypkname", entityMap.get("entitypkname")+"."+entityName);
                    daoMap.put("projectname", configDto.getPname());
                    daoMap.put("projectdes", configDto.getPdesc());
                    daoMap.put("author", configDto.getPauthor());
                    daoMap.put("projecttime", getTime());
                    daoMap.put("daoname", entityMap.get("entityname") + "Dao");
                    daoMap.put("entityname", entityMap.get("entityname"));
                    daoMap.put("eparamname", parseParamName(entityMap.get("entityname").toString()));

                    dao.binding(daoMap);
                    dao.renderTo(new FileOutputStream(baseDir + "/dao/" + daoMap.get("daoname")+".java"));

                    //实现持久映射文件层的源码
                    Template mapper = groupTemplate.getTemplate("/EntityMapperTem.btl");
                    Map<String, Object> mapperMap = new LinkedHashMap<>();
                    mapperMap.put("daopkname", configDto.getPkname() + ".dao." + daoMap.get("daoname"));
                    mapperMap.put("entityname", entityMap.get("entitypkname") + "." + entityMap.get("entityname"));
                    mapperMap.put("insertsql", bufferInsert.toString());
                    mapperMap.put("selectsql", bufferAll.toString());
                    mapper.binding(mapperMap);
                    mapper.renderTo(new FileOutputStream(baseDir + "/mapper/" + entityMap.get("entityname") + "Mapper.xml"));

                    //实现业务接口层的源码
                    Template serviceIntf = groupTemplate.getTemplate("/EntityServiceTem.btl");
                    Map<String, Object> serviceIntfMap = new LinkedHashMap<>();
                    serviceIntfMap.put("servicepkname", configDto.getPkname() + ".service.intf");
                    serviceIntfMap.put("entitypkname", entityMap.get("entitypkname") + "." + entityMap.get("entityname"));
                    serviceIntfMap.put("rpkname", configDto.getPkname()+".vo.R");
                    serviceIntfMap.put("projectname", configDto.getPname());
                    serviceIntfMap.put("projectdes", configDto.getPdesc());
                    serviceIntfMap.put("author", configDto.getPauthor());
                    serviceIntfMap.put("projecttime", getTime());
                    serviceIntfMap.put("servicename", entityMap.get("entityname")+"Service");
                    serviceIntfMap.put("entityname", entityMap.get("entityname"));
                    serviceIntfMap.put("eparamname", daoMap.get("eparamname"));
                    serviceIntf.binding(serviceIntfMap);
                    serviceIntf.renderTo(new FileOutputStream(baseDir + "/service/intf/" + entityMap.get("entityname") + "Service.java"));
                    //实现业务实现层的源码
                    Template serviceImpl = groupTemplate.getTemplate("/EntityServiceImplTem.btl");
                    Map<String, Object> serviceImplMap = new LinkedHashMap<>();
                    serviceImplMap.put("serviceimplpkname", configDto.getPkname() + ".service.impl");
                    serviceImplMap.put("entitypkname", entityMap.get("entitypkname") + "." + entityMap.get("entityname"));
                    serviceImplMap.put("daopkname", daoMap.get("daopkname") + "." + daoMap.get("daoname"));
                    serviceImplMap.put("servicepkname", serviceIntfMap.get("servicepkname") + "." + serviceIntfMap.get("servicename"));
                    serviceImplMap.put("rpkname", configDto.getPkname()+".vo.R");
                    serviceImplMap.put("projectname", configDto.getPname());
                    serviceImplMap.put("projectdes", configDto.getPdesc());
                    serviceImplMap.put("author", configDto.getPauthor());
                    serviceImplMap.put("projecttime", getTime());
                    serviceImplMap.put("serviceimplname", entityMap.get("entityname")+"ServiceImpl");
                    serviceImplMap.put("servicename", serviceIntfMap.get("servicename"));
                    serviceImplMap.put("daoname", daoMap.get("daoname"));
                    serviceImplMap.put("entityname", entityMap.get("entityname"));
                    serviceImplMap.put("eparamname", daoMap.get("eparamname"));
                    serviceImpl.binding(serviceImplMap);
                    serviceImpl.renderTo(new FileOutputStream(baseDir + "/service/impl/" + entityMap.get("entityname") + "ServiceImpl.java"));

                    //实现控制层的源码
                    Template controller = groupTemplate.getTemplate("/EntityControllerTem.btl");
                    Map<String, Object> controllerMap = new LinkedHashMap<>();
                    controllerMap.put("controllerpkname", configDto.getPkname() + ".controller");
                    controllerMap.put("entitypkname", entityMap.get("entitypkname") + "." + entityMap.get("entityname"));
                    controllerMap.put("servicepkname", serviceImplMap.get("servicepkname"));
                    controllerMap.put("rpkname", configDto.getPkname()+".vo.R");
                    controllerMap.put("projectname", configDto.getPname());
                    controllerMap.put("projectdes", configDto.getPdesc());
                    controllerMap.put("author", configDto.getPauthor());
                    controllerMap.put("projecttime", getTime());
                    controllerMap.put("apiurl", "api/"+daoMap.get("eparamname")+"/");
                    controllerMap.put("apides", "实现"+entityMap.get("entityname")+"各种操作");
                    controllerMap.put("controllername", entityMap.get("entityname")+"Controller");
                    controllerMap.put("servicename", entityMap.get("entityname")+"Service");
                    controllerMap.put("entityname", entityMap.get("entityname"));
                    controllerMap.put("eparamname", daoMap.get("eparamname"));
                    controller.binding(controllerMap);
                    controller.renderTo(new FileOutputStream(baseDir + "/controller/" + entityMap.get("entityname") + "Controller.java"));

                    //实现R的源码
                    Template r = groupTemplate.getTemplate("/RTem.btl");
                    Map<String, Object> rMap = new LinkedHashMap<>();
                    rMap.put("vopkname", configDto.getPkname() + ".vo");
                    rMap.put("projectname", configDto.getPname());
                    rMap.put("projectdes", configDto.getPdesc());
                    rMap.put("author", configDto.getPauthor());
                    rMap.put("projecttime", getTime());
                    r.binding(rMap);
                    r.renderTo(new FileOutputStream(baseDir + "/vo/R.java"));

                    //实现Swagger的源码
                    Template swagger = groupTemplate.getTemplate("/SwaggerTem.btl");
                    Map<String, Object> swaggerMap = new LinkedHashMap<>();
                    swaggerMap.put("configpkname", configDto.getPkname() + ".config");
                    swaggerMap.put("projectname", configDto.getPname());
                    swaggerMap.put("projectdes", configDto.getPdesc());
                    swaggerMap.put("author", configDto.getPauthor());
                    swaggerMap.put("projecttime", getTime());
                    swaggerMap.put("controllerpkname", controllerMap.get("controllerpkname"));
                    swagger.binding(swaggerMap);
                    swagger.renderTo(new FileOutputStream(baseDir + "/config/SwaggerConfig.java"));
                }
            }
            //生成压缩文件 zip
            ByteArrayOutputStream baos=new ByteArrayOutputStream();
            CompressUtil.compressZip(FileUtil.CODE_DIR,baos);
            //上传OSS
            String url=AliOssUtil.upload(SystemConfig.OSS_BNAME,FileUtil.CODE_DIR+".zip", baos.toByteArray());
            //返回OSS路径
            return url;
        }catch (IOException e){
            //递归删除已经生成的
        }finally {
            //都结束之后将生成的文件夹全部删除
            FileUtil.delDir(FileUtil.CODE_DIR);
        }
        return null;
    }
}
